/**
 * 
 */
package com.gmail.sabuj.career.qna.core;

import java.util.Iterator;

/**
 * @author Sabuj
 *
 */
public class CircularLinkedList<T> implements Iterable<T>{

	protected Node head;
	protected Node tail;
	
	public CircularLinkedList() {
		head = null;
	}
	
	public boolean isEmpty(){
		return (head == null);
	}
	
	public void add(T item){
		if(isEmpty()){
			Node node = new Node(item);
			head = node;
			tail = head;
			tail.next = head;
		} else{
			Node node = new Node(item);
			tail.next = node;
			node.next = head;
			tail = node;
		}
	}
	
	public void addAll(T ... items){
		if(null != items && items.length > 0){
			for (T t : items) {
				add(t);
			}
		}
	}
	
	public void swapValues(final Node a, final Node b){
		if(a != null && b != null){
			T temp = a.value;
			a.value = b.value;
			b.value = temp;
		}
	}
	
	
	
	public Iterator<T> iterator() {
		return new CircularLinkedListIterator();
	}
	
	public void print(){
		Iterator<T> iterator = iterator();
		while(iterator.hasNext()){
			T value = iterator.next();
			System.out.print(
					(null != value) ? value : "NULL"
					);
			System.out.print(',');
		}
		System.out.println();
	}
	
	private final class CircularLinkedListIterator implements Iterator<T>{

		Node first;
		Node last;
		
		public CircularLinkedListIterator() {
			first = head;
			last = tail;
		}
		
		public boolean hasNext() {
			if(isEmpty())
				return false;
			return first != last;
		}

		public T next() {
			T value = first.value;
			first = first.next;
			if(first.next == last && last.next == head)
				last = last.next;
			return value;
		}

		public void remove() {
			// TODO Auto-generated method stub
			
		}
		
	}
	
	
	protected final class Node{
		private T value;
		private Node next;
		
		Node() {
			this(null);
		}
		
		Node(T value) {
			this.value = value;
		}
		
		public T getValue() {
			return value;
		}

		public void setValue(T value) {
			this.value = value;
		}

		public Node getNext() {
			return next;
		}

		public void setNext(Node next) {
			this.next = next;
		}

		@Override
		public String toString() {
			return (null != value) ? value.toString() : "NULL";
		}
	}


	
}
